4.3 解惑rJava R与Java的高速通道

问题

JAVA和R能不能双向通信?

rJava R与Java的高速通道

引言

Java语言在工业界长期处于霸主地位,Java语法、JVM、JDK、Java开源库,在近10年得到了爆发式的发展,几乎覆盖了应用开发的所有领域。伴随着Java的全领域发展,问题也随之而来了。语法越来越复杂,近似的项目越来越多,学好Java变得很难。对于没有IT背景的统计人员,学用Java更是难于上青天。

R一直是统计圈内处于佼佼者的语言,语法简单,学习曲线不太长也不太陡。如果能结合Java的通用性和R的专业性,碰撞出的火花,将会缤纷绚烂。本节将介绍R与Java连接的高速通道,rJava实现双向通信方案。

4.3.1 rJava介绍

rJava是一个R语言和Java语言的通信接口,通过底层JNI实现调用,允许在R中直接调用Java的对象和方法。rJava还提供了Java调用R的功能,是通过JRI(Java/R Interface)实现的。JRI现在已经被嵌入到rJava的包中,我们也可以单独试用这个功能。现在rJava包已经成为很多基于Java开发R包的基础功能组件。正是由于rJava是底层接口,并使用JNI作为接口调用,所以效率非常高。在JRI的方案中,Java虚拟机(JVM)通过内存直接加载R的计算引擎,调用过程性能几乎无损耗,因此是非常高效的连接通道,是R和Java通信的首选开发包。

4.3.2 rJava安装

本节使用的Linux系统环境是:

  • Linux: Ubuntu 12.04.2 LTS 64bit
  • R: 3.0.1 x86_64-pc-linux-gnu
  • Java: SUN 1.6.0_29 64bit

注:rJava同时支持Win7环境和Linux环境。

安装rJava包时,笔者建议使用root权限来安装rJava包。因为rJava是跨平台调用的一个基础包,后面讲到的RHadoop项目也是基于rJava开发的,当跨平台的程序调用时,在Linux下会有权限检查,为了减少错误,建议以root权限安装rJava包。

这里在安装rJava之前,假设读者在Linux系统中已经安装好了Java环境。Java环境的安装,请参考附录A。

~ sudo R CMD javareconf       # 以root权限配置rJava环境
~ sudo R                       # 以root权限启动R
> install.packages("rJava")  # 安装rJava包
> library(rJava)      # 加载rJava包

4.3.3 rJava实现R调用Java

在R环境中,使用rJava包编程。

> search()                       # 检查当前环境已加载的包
 [1] ".GlobalEnv"        "package:rJava"     "package:stats"
 [4] "package:graphics"  "package:grDevices" "package:utils"
 [7] "package:datasets"  "package:methods"   "Autoloads"
[10] "package:base"

> .jinit()                #启动JVM
> s <- .jnew("java/lang/String", "Hello World!")   #声明并赋值到字符串
> s
[1] "Java-Object{Hello World!}"

> .jcall(s,"I","length")     #查看字符串长度
[1] 12
> .jcall(s,"I","indexOf","World")  #索引World的位置
[1] 6

> .jmethods(s,"concat")      #查看concat的方法声明
[1] "public java.lang.String java.lang.String.concat(java.lang.String)"
> .jcall(s,"Ljava/lang/String;","concat",s)   #使用concat方法连接字符串
[1] "Hello World!Hello World!"

> print(s)      #打印字符串对象
[1] "Java-Object{Hello World!}"
> .jstrVal(s)      #打印字符串值
[1] "Hello World!"

rJava优化过的方法调用,用$来调用方法

> s$length()    #同.jcall(s,"I","length")
[1] 12
> s$indexOf("World")  #同.jcall(s,"I","indexOf","World")
[1] 6

4.3.4 rJava(JRI)实现Java调用R (win7)

在win7中安装rJava,系统环境是:

  • Win7: x86_64-w64-mingw32/x64 (64-bit)
  • R: version 3.0.1
  • JAVA : SUN JDK 1.6.0_45 64bit

设置环境变量

PATH: C:\Program Files\R\R-3.0.1\bin\x64;D:\toolkit\java\jdk6\bin;;D:\toolkit\java\jdk6\jre\bin\server
JAVA_HOME: D:\toolkit\java\jdk6
CLASSPATH: C:\Program Files\R\R-3.0.1\library\rJava\jri

在R中安装rJava。

~ R   # 启动R程序
> install.packages("rJava")   # 安装rJava包
> library(rJava)   #加载rJava
> .jinit()
> s <- .jnew("java/lang/String", "Hello World!")   #R调用Java变量测试
> s
[1] "Java-Object{Hello World!}"

启动Eclipse编写程序,如图4-5所示。

在Eclipse创建Rserve项目

图4-5 在Eclipse创建Rserve项目

下面我们来写一个Java的类DemoRJava.java,实现Java调用JRI的程序。DemoRJava.java中包括2个方法。

  • main()方法:是Java程序启动的入口,实例化一个demo对象,然后调用callRJava()方法。
  • callRJava()方法:创建Rengine对象,在JVM启动启动R引擎,以字符串的方式向R引擎传两条R的语句,在Java中输出结果.

新建Java程序文件 DemoRJava.java。

package org.conan.r.rjava;

import org.rosuda.JRI.Rengine;

public class DemoRJava {

   /**
    * Main方法用于启动Java应用
    */
    public static void main(String[] args) {
        DemoRJava demo = new DemoRJava();
        demo.callRJava();
    }

    public void callRJava() {
        Rengine re = new Rengine(new String[] { "--vanilla" }, false, null);//实例化 Rengine对象,启动R引擎

        if (!re.waitForR()) {
            System.out.println("Cannot load R");
            return;
        }

        String version = re.eval("R.version.string").asString();//执行一条R的语句
        System.out.println(version); //打印结果

        double[] arr = re.eval("rnorm(10)").asDoubleArray();  //循环打印数组
        for (double a : arr) {
            System.out.print(a + ",");
        }
        re.end();//关闭R引擎
    }
}

在Eclipse启动设置VM参数,如图4-6所示。

-Djava.library.path="C:\Program Files\R\R-3.0.1\library\rJava\jri\x64"

配置Eclipse的启动参数

图4-6 配置Eclipse的启动参数

运行结果:

R version 3.0.1 (2013-05-16)
0.04051018703700011,-0.3321596519938258,0.45642459001166913,-1.1907153494936031,1.5872266854172385,1.3639721994863943,-0.6309712627586983,-1.5226698569087498,-1.0416402147174952,0.4864034017637044,

在Eclipse中完成打包DemoRJava.jar,上传到linux环境,继续测试。

4.3.5 rJava(JRI)实现Java调用R (Ubuntu)

新建目录DemoRJava,上传DemoRJava.jar到DemoRJava,Shell命令如下。

~ mkdir /home/conan/R/DemoRJava
~ cd /home/conan/R/DemoRJava
~ ls -l
-rw-r--r-- 1 conan conan 1328 Aug  8  2013 DemoRJava.jar

运行Jar包

~ export R_HOME=/usr/lib/R
~ java -Djava.library.path=/usr/local/lib/R/site-library/rJava/jri -cp /usr/local/lib/R/site-library/rJava/jri/JRI.jar:/home/conan/R/DemoRJava/DemoRJava.jar org.conan.r.rjava.DemoRJava

运行结果

R version 3.0.1 (2013-05-16)
0.6374494596732511,1.3413824702002808,0.04573045670001342,-0.6885617932810327,0.14970067632722675,-0.3989493870007832,-0.6148250252955993,0.40132038323714453,-0.5385260423222166,0.3459850956295771,

我们完成了R和Java的互调。包括了R通过rJava调用Java,Java通过JRI调用R。并演示了Win7和Linux Ubuntu中的使用方法

results matching ""

    No results matching ""